import ctypes
import os
import sys
import tempfile
import tkinter as tk

from cefpython3 import cefpython as cef
from json import dumps
from pathlib import Path

from src.log import SCRIPTP, HOMEP
from src.common import png2ico, createBrowserSync, TInteractObj, shutdown
from src.winOperator import getHwndsByPID, getWindowTitle


class WebWindow():
    # 定义窗口关闭信号
    window_closed = None
    
    def __init__(self, appid, parent=None):
        super().__init__()

        self.appid = appid
        try:
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
        except Exception as e:
            print(f"设置应用用户模型ID失败: {e}")
        
        # 基本属性设置
        self.transparent_color = '#000001'
        self.root = None
        self.window = None

        self.title = ""
        self.bg_color = "#FFFFFF"
        self.background_image = None
        self.window_radius = 0
        self.padding = 0
        self.topmost = False
        self._fullscreen = False
        
        # 初始鼠标位置
        self.dragPos = None

    def _drawBackgroundShadow(self, width, bg_color, radius, size):
        """创建带阴影的背景图片"""
        try:
            # 创建一个新的RGBA图像，使用self.transparent_color作为底色
            transparent_rgb = hex_to_rgb(self.transparent_color)
            image = Image.new('RGBA', size, (*transparent_rgb, 255))

            draw = ImageDraw.Draw(image)

            # 如果有圆角，绘制圆角矩形
            if radius > 0:
                # 绘制圆角矩形背景
                if isLightTheme(bg_color):
                    draw.rounded_rectangle([(0, 0), (int(size[0]-(width/2)), int(size[1]-(width/2)))], radius=radius, fill=bg_color, width=width, outline='#bbbbbb')
                else:
                    draw.rounded_rectangle([(0, 0), (size[0], size[1])], radius=radius, fill=bg_color, width=0)
            else:
                # 绘制普通矩形背景
                draw.rectangle([(0, 0), (size[0], size[1])], fill=bg_color)

            return image
            
        except Exception as e:
            log.error(f"创建默认阴影图片错误: {e}")
            return None

    def initUI(self, params):
        """显示窗口，添加了异常处理以提高稳定性"""
        try:
            # 根据是否隐藏标题栏分别有2种布局
            # 不隐藏标题栏 1个窗口
            if not params.hideTitleBar:
                self.window = tk.Toplevel()
                self.window.withdraw()
                # self.window.attributes('-alpha', 0)
                self.window.protocol("WM_DELETE_WINDOW", self.close)
            elif params.hideTaskIcon:  # 隐藏标题框和任务栏 1个窗口
                self.window = tk.Toplevel()
                self.window.withdraw()
                # self.window.attributes('-alpha', 0)
                self.window.protocol("WM_DELETE_WINDOW", self.close)
                self.window.overrideredirect(True)
            else:  # 隐藏标题栏但不隐藏任务栏 2个窗口
                self.root = tk.Tk()
                self.root.withdraw()  # 隐藏根节点
                self.root.attributes('-alpha', 0)
                # 监听窗口关闭事件
                self.root.protocol("WM_DELETE_WINDOW", self.close)
                # 监听窗口激活事件
                # 绑定焦点事件到窗口
                self.root.bind("<FocusIn>", self.focusIn)

                self.window = tk.Toplevel(self.root)
                self.window.withdraw()
                # self.window.attributes('-alpha', 0)
                self.window.overrideredirect(True)
            
            # 设置透明色
            try:
                self.window.configure(bg=self.transparent_color)
                self.window.attributes('-transparentcolor', self.transparent_color)
            except Exception:
                pass

            self.title = params.title
            self.window.title(self.title)
            if self.root is not None:
                self.root.title(self.title)
            
            if params.icon is not None and Path(params.icon).is_file():
                if params.icon.endswith('.ico'):
                    self.window.iconbitmap(params.icon)
                    if self.root is not None:
                        self.root.iconbitmap(params.icon)
                elif params.icon.endswith('.png'):
                    with tempfile.NamedTemporaryFile(suffix='.ico', delete=False) as temp_icon:
                        temp_icon_path = Path(temp_icon.name)
                        png2ico(args["icon"], str(temp_icon_path))
                        self.window.iconbitmap(str(temp_icon_path))
                        if self.root is not None:
                            self.root.iconbitmap(str(temp_icon_path))
            
            # 支持全局背景色参数
            self.bg_color = params.backgroundColor
            
            # 支持圆角半径参数
            self.window_radius = params.radius
            
            if params.topmost:
                self.topmost = True
                self.window.attributes('-topmost', self.topmost)
            
            # 处理窗口是否可调整大小
            if params.resizable:
                # TODO
                pass
            # 禁止调整窗口大小
            self.window.resizable(False, False)
            
            # 处理最小宽度和高度
            # if str(args.get("minWidth", "")).isdigit() and str(args.get("minHeight", "")).isdigit():
            #     self.setMinimumSize(int(args["minWidth"]), int(args["minHeight"]))
            
            # 处理窗口大小和位置
            if params.position is not None and isinstance(params.position, (list, tuple)) and len(params.position) >= 4:
                x, y, width, height = params.position
                self.window.geometry(f'{width}x{height}+{x}+{y}')
            if params.isCenter:
                # 获取屏幕的宽度和高度
                screen_width = self.window.winfo_screenwidth()
                screen_height = self.window.winfo_screenheight()

                # 计算窗口的位置
                center_x = int(screen_width/2 - width/2)
                center_y = int(screen_height/2 - height/2)
                
                self.window.geometry(f'{width}x{height}+{center_x}+{center_y}')
            
            # 根据是否隐藏标题栏分别有2种布局
            # 不隐藏标题栏
            if not params.hideTitleBar:
                self.window_radius = 0
                self.padding = 0
            else:  # 隐藏标题栏
                # 只有在隐藏标题栏时并且窗口有圆角时才需要背景图片
                if self.window_radius > 0:
                    self.padding = int(self.window_radius - (self.window_radius / 1.414))

                    window_line_width = 4
                    bg = self._drawBackgroundShadow(window_line_width, self.bg_color, self.window_radius, (width, height))
                    if bg:
                        # 将PIL图像转换为Tkinter可用的PhotoImage，并与正确的窗口实例关联
                        self.bg_photo = ImageTk.PhotoImage(image=bg, master=self.window)
                        # 创建一个标签用于显示背景图片
                        self.background_image = tk.Label(self.window, image=self.bg_photo, bg=self.transparent_color)
                        self.background_image.image = self.bg_photo  # 保持引用，防止被垃圾回收
                        self.background_image.place(x=0, y=0, relwidth=1, relheight=1)

                        self.padding = self.padding + window_line_width
                else:
                    self.padding = 0
            
            # 创建WebView
            f = tk.Frame(self.window)
            f.pack(fill=tk.BOTH, expand=True, padx=self.padding, pady=self.padding)
            self.frame_id = f.winfo_id()
            
            # 创建CEF浏览器
            # 确保CEF消息循环运行
            def message_loop_work():
                cef.MessageLoopWork()
                self.window.after(10, message_loop_work)
            self.window.after(10, message_loop_work)
            # 创建WebView
            try:
                self.windowInfo = cef.WindowInfo()
                self.windowInfo.SetAsChild(self.frame_id, [0, 0, width - self.padding * 2, height - self.padding * 2])
                self.webview = createBrowserSync({
                    "background_color": int(self.transparent_color.lstrip('#'), 16),
                    "web_security_disabled": True
                }, self.windowInfo, 'about:blank', self.title)

                def loading_state_change(browser, is_loading, can_go_back, can_go_forward):
                    zoom = max(params.zoomFactor - 1, 0.0)
                    self.webview.SetZoomLevel(zoom)
                    with open(str(HOMEP.joinpath('rawfile/twebchannel.js')), 'r', encoding='utf-8') as f:
                        code = f.read()
                        self.webview.GetMainFrame().ExecuteJavascript(code)

                self.webview.SetClientCallback('OnLoadingStateChange', loading_state_change)

                self.channel = TInteractObj(self)
                self.js = cef.JavascriptBindings()
                self.js.SetObject("channel", self.channel)
                self.webview.SetJavascriptBindings(self.js)

                # 加载内容
                self.loadPage(params.url if params.url is not None else params.file)
            except Exception as e:
                print(f"创建浏览器失败: {str(e)}")
                raise e

        except Exception as e:
            print(f"显示窗口错误: {e}")
            import traceback
            traceback.print_exc()
    
    def registe(self):
        try:
            hwnd_list = getHwndsByPID(os.getpid())
            hwnd = -1
            for h in hwnd_list:
                if getWindowTitle(h) == self.title:
                    hwnd = h
                    break
            sys.stdout.write(f"窗口信息: {dumps({'pid': os.getpid(), 'hwnd': hwnd})}\n")
            sys.stdout.flush()
        except Exception as e:
            raise Warning(f"设置窗口信息失败: {e}")

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.dragPos = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()
    
    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton and self.dragPos is not None:
            self.move(event.globalPos() - self.dragPos)
            event.accept()
    
    def mouseReleaseEvent(self, event):
        self.dragPos = None
        event.accept()

    def show(self):
        """显示窗口"""
        self.window.deiconify()
        self.window.lift()
        if self.root is not None:
            self.root.deiconify()
    
    def hide(self):
        """隐藏窗口"""
        self.window.withdraw()
        if self.root is not None:
            self.root.withdraw()
    
    def max(self):
        try:
            if (type(self.window).__name__) == 'Toplevel':
                self.window.state('zoomed')
            else:
                self.window.showMaximized()
            if self.background_image is not None:
                self.background_image.forget()
            self.webview.SetAutoResizeEnabled(True, [self.window.winfo_width() - self.padding * 2, self.window.winfo_height() - self.padding * 2], [self.window.winfo_width() - self.padding * 2, self.window.winfo_height() - self.padding * 2])
        except Exception as e:
            print(f'最大化窗口异常: {str(e)}')
    
    def normal(self):
        try:
            if (type(self.window).__name__) == 'Toplevel':
                self.window.state('normal')
            else:
                self.window.showNormal()
            if self.background_image is not None:
                self.background_image.place(x=0, y=0, relwidth=1, relheight=1)
            self.webview.SetAutoResizeEnabled(True, [self.window.winfo_width() - self.padding * 2, self.window.winfo_height() - self.padding * 2], [self.window.winfo_width() - self.padding * 2, self.window.winfo_height() - self.padding * 2])
        except Exception as e:
            print(f'缩放窗口异常: {str(e)}')
    
    def focusIn(self, event):
        """窗口获得焦点事件"""
        self.window.lift()
    
    def loadPage(self, link, callback=None):
        if link is None:
            return
        link = str(link).strip()
        if link.startswith("http"):
            self.url = link
        else:
            us = str(link).split('?')
            if not Path(us[0]).exists():
                raise FileNotFoundError(f"HTML文件不存在: {us[0]}")
            self.url = 'file:///' + link
        self.webview.LoadUrl(self.url)
        if callback is not None:
            try:
                callback()
            except Exception as e:
                print(f"调用回调函数错误: {e}")
                import traceback
                traceback.print_exc()
        
    def close(self):
        shutdown()


def create(parser):
    parser.add_argument("--appid", "-id", type=str, default="com.jb.uiplugin.mqt.window", help="窗口ID")
    parser.add_argument("--title", "-t", type=str, default="H5窗口", help="窗口标题")
    parser.add_argument("--icon", "-i", type=str, default=str(SCRIPTP / 'logo.ico'), help="窗口图标文件路径")
    parser.add_argument("--position", "-p", type=str, default='[0, 0, 800, 600]', help="窗口位置")
    parser.add_argument("--isCenter", "-center", type=lambda x: str(x) != 'False', default=True, help="是否居中窗口")
    parser.add_argument("--url", "-u", type=str, default=None, help="窗口加载的URL")
    parser.add_argument("--file", "-f", type=str, default=None, help="窗口加载的文件路径")
    parser.add_argument("--zoomFactor", "-zf", type=lambda x: float(x), default=1.0, help="窗口缩放因子")
    parser.add_argument("--hideTitleBar", "-htb", type=lambda x: str(x) == 'True', default=False, help="是否隐藏标题栏")
    parser.add_argument("--hideTaskIcon", "-hticon", type=lambda x: str(x) == 'True', default=False, help="是否隐藏任务栏图标")
    parser.add_argument("--topmost", "-top", type=lambda x: str(x) == 'True', default=False, help="是否置顶窗口")
    parser.add_argument("--backgroundColor", "-bg", type=str, default="#FFFFFF", help="窗口背景颜色")
    parser.add_argument("--radius", "-r", type=lambda x: int(x), default=0, help="窗口圆角半径")
    parser.add_argument("--resizable", "-res", type=lambda x: str(x) == 'True', default=False, help="是否可调整窗口大小")
    parser.add_argument("--minSize", "-min", type=str, default='[800, 600]', help="窗口最小尺寸")
    parser.add_argument("--maxSize", "-max", type=str, default='[1920, 1080]', help="窗口最大尺寸")
    params = parser.parse_args()

    if params.appid == 'com.jb.uiplugin.mqt.window':
        print('未指定窗口ID')
    else:
        params.position = eval(params.position)
        params.minSize = eval(params.minSize)
        params.maxSize = eval(params.maxSize)

        root = tk.Tk()
        root.withdraw()
        app = WebWindow(params.appid)
        app.initUI(params)
        app.show()
        app.registe()
        root.mainloop()

